package com.cruzr.opengles.light;

import android.content.Context;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;
import android.util.Log;

import com.cruzr.opengles.utils.MatrixUtils;
import com.cruzr.opengles.utils.ShaderUtils;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

public class GLRender implements GLSurfaceView.Renderer {

    public final static String TAG = "GLRender";

    private Context mContext;

    private int mGlProgramId;
    private int mGlUMatrix;
    private int mGlULightPosition;
    private int mGlAPosition;
    private int mGlACoord;
    private int mGlANormal;
    private int mGlUAmbientStrength;
    private int mGlUDiffuseStrength;
    private int mGlUSpecularStrength;
    private int mGlUBaseColor;
    private int mGlULightColor;

    private float[] mMatrix;
    private float[] mLambMatrix;
    private FloatBuffer mBuffer;

    private int mWidth;
    private int mHeight;

    private float mAmbientStrength = 0.3f;
    private float mDiffuseStrength = 0.5f;
    private float mSpecularStrength = 0.8f;

    private float mLightX = 0.45f;
    private float mLightY = 0.45f;
    private float mLightZ = -1.0f;

    private final float[] mData = new float[]{
            // ---- 位置 ----    ---- 顶点法向量 ----
            // 底面
            -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
             0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
             0.5f,  0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
             0.5f,  0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
            -0.5f,  0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
            -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,

            //顶面
            -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
             0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
             0.5f,  0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
             0.5f,  0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
            -0.5f,  0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
            -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,

            //左面
            -0.5f,  0.5f,  0.5f, -1.0f, 0.0f, 0.0f,
            -0.5f,  0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
            -0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
            -0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
            -0.5f, -0.5f,  0.5f, -1.0f, 0.0f, 0.0f,
            -0.5f,  0.5f,  0.5f, -1.0f, 0.0f, 0.0f,

            //右面
            0.5f,  0.5f,  0.5f, 1.0f, 0.0f, 0.0f,
            0.5f,  0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
            0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
            0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
            0.5f, -0.5f,  0.5f, 1.0f, 0.0f, 0.0f,
            0.5f,  0.5f,  0.5f, 1.0f, 0.0f, 0.0f,

            //前面
            -0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
             0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
             0.5f, -0.5f,  0.5f, 0.0f, -1.0f, 0.0f,
             0.5f, -0.5f,  0.5f, 0.0f, -1.0f, 0.0f,
            -0.5f, -0.5f,  0.5f, 0.0f, -1.0f, 0.0f,
            -0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,

            //后面
            -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
             0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
             0.5f, 0.5f,  0.5f, 0.0f, 1.0f, 0.0f,
             0.5f, 0.5f,  0.5f, 0.0f, 1.0f, 0.0f,
            -0.5f, 0.5f,  0.5f, 0.0f, 1.0f, 0.0f,
            -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f
    };

    public GLRender(Context context) {
        mContext = context;

        mBuffer = ByteBuffer.allocateDirect(mData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
        mBuffer.position(0);
        mBuffer.put(mData);
    }

    public void setLight(float x, float y) {
        //View坐标转成GL坐标
        mLightX = (2 * x - mWidth) / mHeight;
        mLightY = 1 - 2 * y / mHeight;
        Log.i(TAG, "setLight -> mLightX : " + mLightX + ", mLightY : " + mLightY);

        Matrix.setIdentityM(mLambMatrix, 0);
        Matrix.translateM(mLambMatrix, 0, mLightX, mLightY, mLightZ);
        Matrix.scaleM(mLambMatrix, 0, 0.05f, 0.05f, 0.05f);
    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        mGlProgramId = ShaderUtils.createProgram(mContext.getResources(),
                "light/light_vertex.glsl", "light/light_fragment.glsl");
        mGlAPosition = GLES20.glGetAttribLocation(mGlProgramId, "aPosition");
        mGlACoord = GLES20.glGetAttribLocation(mGlProgramId, "aCoord");
        mGlANormal = GLES20.glGetAttribLocation(mGlProgramId, "aNormal");
        mGlUMatrix = GLES20.glGetUniformLocation(mGlProgramId, "uMatrix");
        mGlULightPosition = GLES20.glGetUniformLocation(mGlProgramId, "uLightPosition");
        mGlUAmbientStrength = GLES20.glGetUniformLocation(mGlProgramId, "uAmbientStrength");
        mGlUDiffuseStrength = GLES20.glGetUniformLocation(mGlProgramId, "uDiffuseStrength");
        mGlUSpecularStrength = GLES20.glGetUniformLocation(mGlProgramId, "uSpecularStrength");
        mGlULightColor = GLES20.glGetUniformLocation(mGlProgramId, "uLightColor");
        mGlUBaseColor = GLES20.glGetUniformLocation(mGlProgramId, "uBaseColor");
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        mWidth = width;
        mHeight = height;

        int x = 0;
        int y = 0;
        if (width < height) {
            x = (width - height) / 2;
            width = height;
        } else {
            y = (height - width) / 2;
            height = width;
        }
        GLES20.glViewport(x, y, width, height);

        mMatrix = MatrixUtils.getOriginalMatrix();
        Matrix.scaleM(mMatrix, 0, 0.3f, 0.3f, 0.3f);

        mLambMatrix = MatrixUtils.getOriginalMatrix();
        Matrix.translateM(mLambMatrix, 0, mLightX, mLightY, mLightZ);
        Matrix.scaleM(mLambMatrix, 0, 0.05f, 0.05f, 0.05f);
    }

    @Override
    public void onDrawFrame(GL10 gl) {
        //旋转
        Matrix.rotateM(mMatrix, 0, 2, -1, -1, 1);

        GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
        GLES20.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
        GLES20.glUseProgram(mGlProgramId);
        GLES20.glUniformMatrix4fv(mGlUMatrix, 1, false, mMatrix, 0);

        //环境光强度
        GLES20.glUniform1f(mGlUAmbientStrength, mAmbientStrength);
        //漫反射光强度
        GLES20.glUniform1f(mGlUDiffuseStrength, mDiffuseStrength);
        //镜面光强度
        GLES20.glUniform1f(mGlUSpecularStrength, mSpecularStrength);
        //光源颜色
        GLES20.glUniform3f(mGlULightColor, 1.0f, 1.0f, 1.0f);
        //物体颜色
        GLES20.glUniform4f(mGlUBaseColor, 1.0f, 1.0f, 1.0f, 1.0f);
        //光源位置
        GLES20.glUniform3f(mGlULightPosition, mLightX, mLightY, mLightZ);

        //传入顶点信息
        GLES20.glEnableVertexAttribArray(mGlAPosition);
        mBuffer.position(0);
        GLES20.glVertexAttribPointer(mGlAPosition, 3, GLES20.GL_FLOAT, false, 6 * 4, mBuffer);

        //传入法线信息
        GLES20.glEnableVertexAttribArray(mGlANormal);
        mBuffer.position(3);
        GLES20.glVertexAttribPointer(mGlANormal, 3, GLES20.GL_FLOAT, false, 6 * 4, mBuffer);
        GLES20.glEnable(GLES20.GL_DEPTH_TEST);
        GLES20.glEnable(GLES20.GL_CULL_FACE);
        GLES20.glCullFace(GLES20.GL_FRONT);
        GLES20.glFrontFace(GLES20.GL_CW);

        //绘制立方体
        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, mData.length / 6);

        //绘制光源位置
        GLES20.glUniformMatrix4fv(mGlUMatrix, 1, false, mLambMatrix, 0);
        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, mData.length / 6);

        GLES20.glDisable(GLES20.GL_CULL_FACE);
        GLES20.glDisable(GLES20.GL_DEPTH_TEST);
        GLES20.glDisableVertexAttribArray(mGlAPosition);
        GLES20.glDisableVertexAttribArray(mGlANormal);
    }

}
